home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tech Arsenal 1
/
Tech Arsenal (Arsenal Computer).ISO
/
tek-01
/
dbdoc.zip
/
MEMDOC.C
< prev
next >
Wrap
C/C++ Source or Header
|
1991-12-08
|
14KB
|
545 lines
/**************************************/
/* memdoc.c */
/* dBASE memo file reader */
/* Programmer: Jay Parsons */
/* Version 1.1 12/08/91 */
/* */
/* Changes in 1.1: */
/* removed incorrect rounding */
/* procedure in do_float_var */
/* and replaced it with change */
/* to the print formatting string */
/**************************************/
#include "ctype.h"
#include "math.h"
#include "stdio.h"
#include "string.h"
/**************************************/
/* define statememts */
/**************************************/
#define JULBASE 1721060 /* dBASE Julian for 01/01/0000 */
#define FOURCENTS 146097 /* days in 400 years */
#define SHORTCENT 36524 /* days in 100 years if not /400 */
#define FOURYEARS 1461 /* days in 4 years with a leap year */
#define SHORTYEAR 365 /* days in a year not a leap year */
#define ENDFILE 0x1A
#define MAXNAME 11 /* max size of variable name + 1 */
#define HEADERLEN 32 /* sizeof( struct memheader ) */
#define PUBLIC 0
#define FALSE 0
#define TRUE 1
/**************************************/
/* global declarations */
/**************************************/
struct memheader
{
char name[MAXNAME]; /* variable name */
char type; /* array, char, date, float, num or logic */
unsigned long dataptr; /* useless except 1=bcd, 2=int for dB IV */
char size;
char decimals;
char scope; /* public or private */
char wasted1[13];
} var;
int arr1_subscr, arr2_subscr, dim_1, dim_2, inarray;
extern char file_name[], message[], tempbuff[];
/**************************************/
/* function declarations */
/**************************************/
int memdoc( char *file_name );
int nextvar( FILE *ifile, int inarray );
int do_array( FILE *ifile );
int do_bcd_var( FILE *ifile );
int do_char_var( FILE *ifile );
int do_date_var( FILE *ifile );
int do_float_var( FILE *ifile );
int do_logic_var( FILE *ifile );
int do_num_var( FILE *ifile );
char *dtoc( double jul );
char *dow( double jul );
/******************************************/
/* int memdoc (char *file_name) */
/* Principal routine of this module. */
/* Attempts to open mem file "file_name." */
/* If successful, prints it until reaching*/
/* any error or variable of unknown type. */
/* Closes file and returns 0 or error. */
/******************************************/
int memdoc( char *file_name )
{
int i;
FILE *ifile;
if ( ( ifile = fopen( file_name, "rb" ) ) == NULL )
{ sprintf( message, "Unable to open file %s for reading", file_name );
return( 1 );
}
inarray = FALSE;
while ( ! ( i = nextvar( ifile, inarray ) ) )
printit( i );
fclose( ifile );
return ( i == 2 ? 0 : i );
}
/******************************************/
/* int nextvar( ifile, inarray ) */
/* Reads 32 characters of "ifile" as the */
/* the header of a memvar. Returns 1 if */
/* not a .mem file or error, 2 at eof() */
/* else 0. */
/* Analyzes header, prints name and type, */
/* and calls appropriate routine to read */
/* and display data for the type. The */
/* called routine moves the ifile pointer */
/* to end of data, which should be start */
/* of next header or ENDFILE. */
/* Omits name of variable and substitutes */
/* array address for array elements, due */
/* to parameter "inarray". */
/******************************************/
int nextvar( FILE *ifile, int inarray )
{
/* "F" and "N" routines reversed for dBASE quirk */
char z = ' ', *ptr, vartypes[] = "ACDNLF";
int (*do_ptr[]) () = { do_array, do_char_var,
do_date_var, do_float_var,
do_logic_var, do_num_var };
/* read the next header; return 2 for EOF, 1 for other error */
switch ( fread( &var, 1, HEADERLEN, ifile ) )
{
case HEADERLEN :
break;
case 0 :
if ( getch( ifile ) == EOF )
return 2;
else
{
sprintf( message, "Error reading .mem file %s", file_name );
return 1;
}
case 1 :
/* if only char not ENDFILE, fall thru to default */
if ( var.name[0] == ENDFILE )
return 2;
default :
{
sprintf( message, "Error reading .mem file %s", file_name );
return 1;
}
}
/* get the type bit and pointer to it in vartypes string */
z = var.type & 127; /* strip high bit */
ptr = strchr( vartypes, (int) z );
/* if variable is no known dBase var type */
if ( ptr == NULL )
{
sprintf( message, "Not a .mem file" );
return 1;
}
/* add variable name, or if an array element, its address */
if ( !inarray )
/* sprintf() spec %-12s takes care of padding */
sprintf( message, "%-12s ", var.name );
else
{
if ( var.name[0] != '[' )
{
sprintf( message, "Too few elements for declared array!" );
return 1;
}
if ( !arr2_subscr ) /* one-dimensional array */
sprintf( tempbuff, " [%d] ", arr1_subscr) ;
else /* two-dimensional array */
sprintf( tempbuff, " [%d,%d] ", arr1_subscr, arr2_subscr );
strcpy( message, tempbuff );
}
/* add scope and type - all non-public levels are "private" */
if ( inarray )
strcat( message, " elem " );
else
{
sprintf( tempbuff, " %s ",var.scope == PUBLIC ? "pub" : "prv" );
strcat( message, tempbuff );
}
sprintf( tempbuff, "%c ", ( z == 'N' ? 'F' : z == 'F' ? 'N' : z ) );
strcat( message, tempbuff );
/* now, finally, deal with each type of data as required */
return ( ( *do_ptr[ptr - vartypes] ) ( ifile ) );
}
/***************************************/
/* do_array() */
/***************************************/
int do_array( FILE *ifile )
{
int err;
/* read dimensions (backwards due to C evaluation order) */
if ( fread( &dim_2, 2, 1, ifile ) + fread( &dim_1, 2, 1, ifile ) != 2 )
{
sprintf( message, "Unable to read array dimensions" );
return 1;
}
/* add dimensions as data for A type */
if ( dim_2 )
{
sprintf( tempbuff, "[%d,%d]", dim_1, dim_2 );
strcat( message, tempbuff );
}
else
{
arr2_subscr = 0;
sprintf( tempbuff, "[%d]", dim_1 );
strcat( message, tempbuff );
}
inarray = TRUE;
printit( 0 );
/* get elements, almost but not exactly like other data */
for ( arr1_subscr = 1; arr1_subscr <= dim_1; arr1_subscr++ )
if ( !dim_2 )
{
err = nextvar( ifile, inarray );
printit( err );
if ( err )
return err;
}
else
for (arr2_subscr = 1; arr2_subscr <= dim_2; arr2_subscr++ )
{
err = nextvar( ifile, inarray );
printit( err );
if ( err )
return err;
}
inarray = FALSE;
*message = '\0'; /* suppress extra line feed on return */
return 0;
}
/***************************************/
/* do_char_var() */
/***************************************/
int do_char_var( FILE *ifile )
{
int spaces;
char *c;
if ( fread( tempbuff, var.size, 1, ifile ) != 1 )
{
strcpy( message, "Unable to read character variable" );
return 1;
}
strcat( message, "\"" );
strcat( message, tempbuff );
strcat( message, "\"" );
return 0;
}
/***************************************/
/* do_date_var() */
/* */
/* The value of a null date is 10^100 */
/***************************************/
int do_date_var( FILE *ifile )
{
double julian;
char *days[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" } ;
if ( fread( &julian, 8, 1, ifile ) !=1 )
{
strcpy( message, "Can't read a date" );
return 1;
}
if ( julian <= JULBASE + SHORTCENT ) /* January 1, 100 */
{
strcpy( message, "Not a valid dBASE date" );
return 1;
}
if ( julian == 1.e100 )
strcat( message, "{ / / }" );
else
{
strcat( message, days[ ( ( unsigned long ) julian + 1 ) % 7 ] );
strcat( message, ", " );
strcat( message, dtoc( julian ) );
}
return 0;
}
/***************************************/
/* dtoc( julian ) */
/* */
/* Convert a date given as a dBASE */
/* Julian double into "1 Oct 1990" */
/* */
/* There are shorter algorithms, but */
/* they are much less intuitive. */
/***************************************/
char *dtoc( double julian )
{
int daysin[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
char *month[] = { "Jan","Feb","Mar","Apr",
"May","Jun","Jul","Aug",
"Sep","Oct","Nov","Dec" };
char *ptr, strdate[12];
unsigned int era, cent, quad, leap, yr, year, mo = 0;
unsigned long tempdate;
/* adjust number in tempdate to days since end of 1 BC */
tempdate = ( unsigned long ) julian - JULBASE;
/* find number of four-century eras A.D. and adjust */
era = tempdate / FOURCENTS;
year = 400 * era;
tempdate %= FOURCENTS;
/* first year of each 400 is a leap year */
if ( tempdate < 366 )
leap = 1;
else
/* adjust to pretend all centuries are short ones */
{
tempdate -= 1;
cent = tempdate / SHORTCENT;
year += cent * 100;
tempdate %= SHORTCENT;
/* first year of century is nonleap, else adjust back */
if ( tempdate < 365 )
leap = 0;
else
{
tempdate += 1;
quad = tempdate / FOURYEARS;
year += quad * 4;
tempdate %= FOURYEARS;
/* first year of each four is a leap year, so adjust */
if ( tempdate > 365 )
{
tempdate -= 1;
yr = tempdate / SHORTYEAR;
year += yr;
tempdate %= SHORTYEAR;
}
leap = !( year % 4 );
}
}
/* convert from offset 0 into year to day 1, etc. */
tempdate += 1;
/* mo[1] is the second month in C, Feb. 29 is day 60 */
if ( leap && ( tempdate == 60 ) )
{
mo = 1;
tempdate = 29;
}
else
{
/* subtract Feb. 29 if our date is later */
if ( leap && ( tempdate > 60 ) )
tempdate--;
for ( ; tempdate > daysin[mo]; tempdate -= daysin[mo], mo++ )
;
}
ltoa( tempdate, tempbuff, 10 );
strcpy( strdate, tempbuff );
strcat( strdate, " " );
strcat( strdate, month[mo] );
strcat( strdate, ", " );
itoa( year, tempbuff, 10 );
strcat( strdate, tempbuff );
return strdate;
}
/***************************************/
/* do_float_var() */
/***************************************/
int do_float_var( FILE *ifile )
{
double fvar;
char prefix[] = "% G.";
char format[8];
if ( fread( &fvar, 8, 1, ifile ) != 1 )
{
strcpy( message, "Can't read a float value" );
return 1;
}
strcpy( format, prefix );
/* round off decimals beyond those specified */
sprintf( tempbuff, "%d", var.decimals );
strcat( format, tempbuff );
sprintf( tempbuff, format, fvar );
strcat( message, tempbuff );
return 0;
}
/***************************************/
/* do_logic_var() */
/***************************************/
int do_logic_var( FILE *ifile )
{
unsigned char s;
if ( fread( &s, 1, 1, ifile ) != 1 )
{
strcpy( message, "Can't read a logical value" );
return 1;
}
if ( s > 1 )
{
strcpy( message, "Not a valid logical value" );
return 1;
}
sprintf( tempbuff, "%s", s == FALSE ? ".F." : ".T." );
strcat( message, tempbuff );
return 0;
}
/***************************************/
/* do_num_var() */
/***************************************/
int do_num_var( FILE * ifile )
{
int numvar;
if ( var.dataptr == 1 )
return do_bcd_var( ifile );
if ( fread( &numvar, 2, 1, ifile ) !=1 )
{
strcpy( message, "Can't read integer" );
return 1;
}
sprintf( tempbuff, "%d", numvar );
strcat( message, tempbuff );
return 0;
}
/***************************************/
/* do_bcd_var() */
/***************************************/
int do_bcd_var( FILE *ifile )
{
int exponent, precision, place, signword;
register int i, j = 2;
char bcd[12], longnum[] = " ";
if ( fread( bcd, 12, 1, ifile ) != 1 )
{
strcpy( message, "Can't read BCD number" );
return 1;
}
/* first bit is sign, then 5 precision and 10 exponent biased +308 */
signword = 256 * (int) bcd[1] + (int) bcd[0];
longnum[0] = ((signword & 0x8000) == 0) ? ' ' : '-';
precision = (signword >> 10) & 0x1F;
exponent = (signword & 0x3FF) - 308;
/* we can ignore trailing zeroes within precision */
for ( i = (precision + 3)/2; i >= 2; precision-- )
if ( precision % 2 )
if ( (bcd[i] >> 4) )
break;
else
i--;
else
if ( (bcd[i] & 0x0F) )
break;
/* Place decimal point if necessary */
/* and add leading zeroes after decimal point */
if ( exponent > 20 || exponent < 1 )
{
longnum[1] = '.';
if ( exponent > 20 || precision - exponent > 19 )
place = 2;
else
{
place = 2 - exponent;
for ( i = 2; i < place; i++ )
longnum[i] = '0';
}
}
else
{
place = 1;
if ( precision > exponent )
longnum[exponent+1] = '.';
}
/* now add the digits, skipping over the decimal point */
for ( i = 1; i <= precision; i++ )
{
if ( longnum[place] == '.' )
place++;
if ( i % 2 )
longnum[place++] = 48 + ( bcd[j] >> 4 ) ;
else
longnum[place++] = 48 + ( bcd[j++] & 0x0F );
}
/* add trailing zeroes if needed */
if ( exponent < 21 )
{
i = precision;
while ( exponent > i++ )
longnum[place++] = '0';
}
longnum[place] = '\0';
strcat( message, longnum );
/* and exponent if any */
if ( exponent > 20 || precision - exponent > 18 )
{
sprintf( tempbuff, "E%+d", exponent ); /* show plus sign */
strcat( message, tempbuff );
}
return 0;
}
/* EOF */